// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "../../core/include/fxcrt/fx_xml.h"
#include "../../public/fpdf_ext.h"
#include "../include/fsdk_define.h"

#define  FPDFSDK_UNSUPPORT_CALL 100

class CFSDK_UnsupportInfo_Adapter
{
public:
    CFSDK_UnsupportInfo_Adapter(UNSUPPORT_INFO* unsp_info){ m_unsp_info = unsp_info;}
//  FX_BOOL NeedToPauseNow();
    void ReportError(int nErrorType);

private:
    UNSUPPORT_INFO* m_unsp_info;
};

void CFSDK_UnsupportInfo_Adapter::ReportError(int nErrorType)
{
    if(m_unsp_info && m_unsp_info->FSDK_UnSupport_Handler)
    {
        m_unsp_info->FSDK_UnSupport_Handler(m_unsp_info,nErrorType);
    }
}

void FreeUnsupportInfo(void* pData)
{
    CFSDK_UnsupportInfo_Adapter * pAdapter = (CFSDK_UnsupportInfo_Adapter *)pData;
    delete pAdapter;
}

FX_BOOL FPDF_UnSupportError(int nError)
{
    CFSDK_UnsupportInfo_Adapter * pAdapter = (CFSDK_UnsupportInfo_Adapter *)CPDF_ModuleMgr::Get()->GetPrivateData((void *)FPDFSDK_UNSUPPORT_CALL);

    if(!pAdapter)
        return FALSE;
    pAdapter->ReportError(nError);
    return TRUE;
}

DLLEXPORT FPDF_BOOL STDCALL FSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO* unsp_info)
{
    if (!unsp_info || unsp_info->version!=1)
        return FALSE;
    CFSDK_UnsupportInfo_Adapter * pAdapter = new CFSDK_UnsupportInfo_Adapter(unsp_info);

    CPDF_ModuleMgr::Get()->SetPrivateData((void *)FPDFSDK_UNSUPPORT_CALL,pAdapter, &FreeUnsupportInfo);

    return TRUE;
}

void CheckUnSupportAnnot(CPDF_Document * pDoc, CPDF_Annot* pPDFAnnot)
{
    CFX_ByteString cbSubType = pPDFAnnot->GetSubType();
    if(cbSubType.Compare("3D") == 0)
    {
        FPDF_UnSupportError(FPDF_UNSP_ANNOT_3DANNOT);
    }
    else if(cbSubType.Compare("Screen") ==0)
    {
        CPDF_Dictionary* pAnnotDict = pPDFAnnot->GetAnnotDict();
        CFX_ByteString cbString;
        if(pAnnotDict->KeyExist("IT"))
            cbString = pAnnotDict->GetString("IT");
        if(cbString.Compare("Img") != 0)
            FPDF_UnSupportError(FPDF_UNSP_ANNOT_SCREEN_MEDIA);
    }
    else if(cbSubType.Compare("Movie") ==0)
    {
        FPDF_UnSupportError(FPDF_UNSP_ANNOT_MOVIE);
    }
    else if(cbSubType.Compare("Sound") ==0)
    {
        FPDF_UnSupportError(FPDF_UNSP_ANNOT_SOUND);
    }
    else if(cbSubType.Compare("RichMedia") ==0)
    {
        FPDF_UnSupportError(FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA);
    }
    else if(cbSubType.Compare("FileAttachment") ==0)
    {
        FPDF_UnSupportError(FPDF_UNSP_ANNOT_ATTACHMENT);
    }
    else if(cbSubType.Compare("Widget") ==0)
    {
        CPDF_Dictionary* pAnnotDict = pPDFAnnot->GetAnnotDict();
        CFX_ByteString cbString;
        if(pAnnotDict->KeyExist("FT"))
        {
            cbString = pAnnotDict->GetString("FT");
        }
        if(cbString.Compare("Sig") == 0)
        {
            FPDF_UnSupportError(FPDF_UNSP_ANNOT_SIG);
        }
    }

}

FX_BOOL CheckSharedForm(CXML_Element * pElement, CFX_ByteString cbName)
{
    int count = pElement->CountAttrs();
    int i=0;
    for (i = 0; i < count; i++)
    {
        CFX_ByteString space, name;
        CFX_WideString value;
        pElement->GetAttrByIndex(i, space, name, value);
        if (space == FX_BSTRC("xmlns") && name == FX_BSTRC("adhocwf") && value ==  L"http://ns.adobe.com/AcrobatAdhocWorkflow/1.0/")
        {
            CXML_Element *pVersion = pElement->GetElement("adhocwf",cbName);
            if (!pVersion)
                continue;
            CFX_WideString wsContent = pVersion->GetContent(0); // == 1.1
            int nType = wsContent.GetInteger();
            switch(nType)
            {
            case 1:
                FPDF_UnSupportError(FPDF_UNSP_DOC_SHAREDFORM_ACROBAT);
                break;
            case 2:
                FPDF_UnSupportError(FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM);
                break;
            case 0:
                FPDF_UnSupportError(FPDF_UNSP_DOC_SHAREDFORM_EMAIL);
                break;
            }
        }
    }

    FX_DWORD nCount = pElement->CountChildren();
    for(i=0; i<(int)nCount; i++)
    {
        CXML_Element::ChildType childType = pElement->GetChildType(i);
        if(childType == CXML_Element::Element)
        {
            CXML_Element * pChild = pElement->GetElement(i);
            if(CheckSharedForm(pChild, cbName))
                return TRUE;
        }
    }
    return FALSE;
}

void CheckUnSupportError(CPDF_Document * pDoc, FX_DWORD err_code)
{
    // Security
    if(err_code == FPDF_ERR_SECURITY)
    {
        FPDF_UnSupportError(FPDF_UNSP_DOC_SECURITY);
        return ;
    }
    if(!pDoc)
        return ;

    // Portfolios and Packages
    CPDF_Dictionary * pRootDict = pDoc->GetRoot();
    if(pRootDict)
    {
        CFX_ByteString cbString;
        if(pRootDict->KeyExist("Collection"))
        {
            FPDF_UnSupportError(FPDF_UNSP_DOC_PORTABLECOLLECTION);
            return ;
        }
        if(pRootDict->KeyExist("Names"))
        {
            CPDF_Dictionary* pNameDict = pRootDict->GetDict("Names");
            if (pNameDict && pNameDict->KeyExist("EmbeddedFiles"))
            {
                FPDF_UnSupportError(FPDF_UNSP_DOC_ATTACHMENT);
                return;
            }
            if (pNameDict && pNameDict->KeyExist("JavaScript"))
            {
                CPDF_Dictionary* pJSDict = pNameDict->GetDict("JavaScript");
                CPDF_Array * pArray = pJSDict ? pJSDict->GetArray("Names") : NULL;
                if (pArray) {
                    int nCount = pArray->GetCount();
                    for(int i=0; i<nCount; i++)
                    {
                        CFX_ByteString cbStr = pArray->GetString(i);
                        if(cbStr.Compare("com.adobe.acrobat.SharedReview.Register") == 0)
                        {
                            FPDF_UnSupportError(FPDF_UNSP_DOC_SHAREDREVIEW);
                            return;
                        }
                    }
                }
            }
        }
    }

    // SharedForm
    CPDF_Metadata metaData;
    metaData.LoadDoc(pDoc);
    CXML_Element * pElement = metaData.GetRoot();
    if(pElement)
        CheckSharedForm(pElement, "workflowType");

    // XFA Forms
    CPDF_InterForm * pInterForm = new CPDF_InterForm(pDoc,FALSE);
    if (pInterForm->HasXFAForm())
    {
        FPDF_UnSupportError(FPDF_UNSP_DOC_XFAFORM);
    }
    delete pInterForm;
}

DLLEXPORT int FPDFDoc_GetPageMode(FPDF_DOCUMENT document)
{
    if (!document)
        return PAGEMODE_UNKNOWN;

    CPDF_Dictionary* pRoot = ((CPDF_Document*)document)->GetRoot();
    if (!pRoot)
        return PAGEMODE_UNKNOWN;

    CPDF_Object* pName = pRoot->GetElement("PageMode");
    if (!pName)
        return PAGEMODE_USENONE;

    CFX_ByteString strPageMode = pName->GetString();
    if (strPageMode.IsEmpty()||strPageMode.EqualNoCase("UseNone"))
        return PAGEMODE_USENONE;
    if (strPageMode.EqualNoCase("UseOutlines"))
        return PAGEMODE_USEOUTLINES;
    if (strPageMode.EqualNoCase("UseThumbs"))
        return PAGEMODE_USETHUMBS;
    if (strPageMode.EqualNoCase("FullScreen"))
        return PAGEMODE_FULLSCREEN;
    if (strPageMode.EqualNoCase("UseOC"))
        return PAGEMODE_USEOC;
    if (strPageMode.EqualNoCase("UseAttachments"))
        return PAGEMODE_USEATTACHMENTS;

    return PAGEMODE_UNKNOWN;
}
